home *** CD-ROM | disk | FTP | other *** search
/ Delphi Informant Complete 1995 - 2000 / Delphi Informant Complete 1995 to 2000.iso / Delphi Informant Magazine Complete Works SOURCE CODE 1998.rar / 1998 / Nov / di9811gd / Example3 / Unit1.pas < prev   
Pascal/Delphi Source File  |  1998-03-10  |  6KB  |  214 lines

  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls;
  8.  
  9. type
  10.   { TLightThread }
  11.   {* For easy management of threads.                                          *}
  12.   {* Allows a thread to be "created" with a passed thread function. The       *}
  13.   {* function will exit cleanly when ThreadExiting is set to true, or         *}
  14.   {* "nastily" after a timeout of ThreadExitTimeout milliseconds.             *}
  15.   {* For the purposes of this example, though, we are pretty assured that the *}
  16.   {* ThreadFunc used will always exit cleanly... (How else to demonstrate     *}
  17.   {* a thread-safe DLL?)                                                      *}
  18.   TLightThread = class(TObject)
  19.   protected
  20.     FThreadHandle: THandle;
  21.     FThreadID: DWord;
  22.     FCS: TRTLCriticalSection;
  23.     FThreadExiting: Boolean;
  24.     function GetThreadExiting: Boolean;
  25.   public
  26.     constructor Create(ThreadFunc: TThreadFunc);
  27.     destructor Destroy; override;
  28.     property ThreadExiting: Boolean read GetThreadExiting;
  29.     property ThreadHandle: THandle read FThreadHandle;
  30.     property ThreadID: DWord read FThreadID;
  31.   end;
  32.  
  33.   { TForm1 }
  34.   TForm1 = class(TForm)
  35.     btnLoad: TButton;
  36.     btnUnload: TButton;
  37.     lbThreads: TListBox;
  38.     Label1: TLabel;
  39.     btnNewThread: TButton;
  40.     btnCloseThread: TButton;
  41.     procedure FormCreate(Sender: TObject);
  42.     procedure FormDestroy(Sender: TObject);
  43.     procedure btnLoadClick(Sender: TObject);
  44.     procedure btnUnloadClick(Sender: TObject);
  45.     procedure btnNewThreadClick(Sender: TObject);
  46.     procedure btnCloseThreadClick(Sender: TObject);
  47.   private
  48.     { Private declarations }
  49.   public
  50.     { Public declarations }
  51.     LibHandle: THandle;
  52.     ThreadList: TList;
  53.     procedure FreeLib;
  54.     procedure NewThread;
  55.     procedure CloseThread(Idx: Integer); { Close indexed thread. }
  56.     procedure CloseThreads;
  57.   end;
  58.  
  59. var
  60.   Form1: TForm1;
  61.  
  62. const
  63.   ThreadSleepLength = 50; // 50 ms.
  64.   ThreadExitTimeout = 10000;
  65.  
  66. implementation
  67.  
  68. {$R *.DFM}
  69.  
  70. function ThreadFunc(Parameter: Pointer): Integer;
  71. begin
  72.   while (not TLightThread(Parameter).ThreadExiting) do
  73.     Sleep(ThreadSleepLength);
  74.   result := 0;
  75. end;
  76.  
  77. { TLightThread }
  78. constructor TLightThread.Create(ThreadFunc: TThreadFunc);
  79. begin
  80.   InitializeCriticalSection(FCS);
  81.   FThreadExiting := False;
  82.   try
  83.     FThreadHandle :=
  84.       BeginThread(nil, 0, ThreadFunc, Pointer(Self), 0, FThreadID);
  85.   except
  86.     on E: Exception do begin
  87.       DeleteCriticalSection(FCS);
  88.       raise;
  89.     end;
  90.   end;
  91. end;
  92.  
  93. destructor TLightThread.Destroy;
  94. begin
  95.   EnterCriticalSection(FCS);
  96.   try
  97.     FThreadExiting := True;
  98.   finally
  99.     LeaveCriticalSection(FCS);
  100.   end;
  101.   WaitForSingleObject(FThreadHandle, ThreadExitTimeout);
  102.   CloseHandle(FThreadHandle);
  103.   DeleteCriticalSection(FCS);
  104.   inherited;
  105. end;
  106.  
  107. function TLightThread.GetThreadExiting: Boolean;
  108. begin
  109.   EnterCriticalSection(FCS);
  110.   try
  111.     result := FThreadExiting;
  112.   finally
  113.     LeaveCriticalSection(FCS);
  114.   end;
  115. end;
  116.  
  117.  
  118. { TForm1 }
  119.  
  120. procedure TForm1.FormCreate(Sender: TObject);
  121. begin
  122.   LibHandle := 0;
  123.   ThreadList := TList.Create;
  124. end;
  125.  
  126. procedure TForm1.FormDestroy(Sender: TObject);
  127. begin
  128.   FreeLib;                           // Free the library, if necessary
  129.   CloseThreads;                      // Guarantee that threads are closed.
  130.   ThreadList.Free;                   // Free the list of threads.
  131. end;
  132.  
  133. procedure TForm1.btnLoadClick(Sender: TObject);
  134. begin
  135.   if LibHandle = 0 then
  136.     LibHandle := LoadLibrary('Dll3.dll');
  137. end;
  138.  
  139. procedure TForm1.btnUnloadClick(Sender: TObject);
  140. begin
  141.   FreeLib;                           // Free the library, if necessary
  142. end;
  143.  
  144. procedure TForm1.btnNewThreadClick(Sender: TObject);
  145. begin
  146.   NewThread;
  147. end;
  148.  
  149. procedure TForm1.btnCloseThreadClick(Sender: TObject);
  150. begin
  151.   CloseThread(lbThreads.ItemIndex);
  152. end;
  153.  
  154. procedure TForm1.FreeLib;
  155. var
  156.   i, Cnt: Integer;
  157. begin
  158.   {* In comments is the appropriate way for a calling application
  159.      to free its library when it has multiple threads; however, for
  160.      the purpose of the example, we _just_ unload the library *}
  161.   FreeLibrary(LibHandle);
  162.   LibHandle := 0;
  163.   {if LibHandle <> 0 then begin
  164.     try
  165.       Cnt := ThreadList.Count;
  166.       for i := 0 to Cnt - 1 do CloseThread(0);
  167.       FreeLibrary(LibHandle);
  168.     finally
  169.       LibHandle := 0;
  170.     end;
  171.   end;}
  172. end;
  173.  
  174. procedure TForm1.NewThread;
  175. var
  176.   Thd: TLightThread;
  177. begin
  178.   { Create a thread }
  179.   Thd := TLightThread.Create(ThreadFunc);
  180.   { If thread was created successfully, then add the thread handle to
  181.     ThreadList, increment thread count and add an "identifier" to
  182.     the ListBox (for identification purposes only). }
  183.   ThreadList.Add(Pointer(Thd));
  184.   lbThreads.Items.Add('Thread #' + IntToStr(Thd.ThreadHandle));
  185.   lbThreads.ItemIndex := lbThreads.Items.Count - 1;
  186. end;
  187.  
  188. procedure TForm1.CloseThread(Idx: Integer);
  189. begin
  190.   if (Idx >= 0) and (Idx < ThreadList.Count) then begin
  191.     TLightThread(ThreadList.Items[Idx]).Free;
  192.     ThreadList.Delete(Idx);  ThreadList.Pack;
  193.     lbThreads.Items.Delete(Idx);
  194.     if (Idx = ThreadList.Count) then
  195.       lbThreads.ItemIndex := Idx - 1
  196.     else
  197.       lbThreads.ItemIndex := Idx;
  198.   end;
  199. end;
  200.  
  201. procedure TForm1.CloseThreads;
  202. var
  203.   i, Cnt: Integer;
  204. begin
  205.   Cnt := ThreadList.Count;
  206.   for i := 0 to Cnt - 1 do CloseThread(0);
  207. end;
  208.  
  209. initialization
  210.  
  211.   IsMultiThread := True;
  212.  
  213. end.
  214.